#pragma once
#include <iostream>
#include <cstdarg>
#include <strings.h>
#include <sys/types.h>
#include <unistd.h>
#include "err.hpp"

namespace zxf
{

// 定义日志等级
#define DEBUG 0   // bug
#define NORMAL 1  // 正常
#define WARNING 2 // 警告
#define ERROR 3   // 错误
#define FATAL 4   // 致命错误

    // 我们传入得错误信息接口是 :
    //  logMessage(日志等级, foemat...);

    // 打印/或者输出到文件得信息格式是 :
    //  [日志等级] [时间戳/时间] [pid] [error_messge]
    // 例如:
    //  [WARNING] [2023-05-11 18:09:08] [123] [创建socket失败]

    // 这是一个 可变参数得函数接口
    // 我们先学习C语言和c++得可变参数怎么写
    // 学习一下一套函数

    // #include <stdio.h>
    // int printf(const char *format, ...);
    // int fprintf(FILE *stream, const char *format, ...);
    // int sprintf(char *str, const char *format, ...);
    // int snprintf(char *str, size_t size, const char *format, ...);

    // #include <stdarg.h>
    // int vprintf(const char *format, va_list ap);
    // int vfprintf(FILE *stream, const char *format, va_list ap);
    // int vsprintf(char *str, const char *format, va_list ap);
    // int vsnprintf(char *str, size_t size, const char *format, va_list ap);

    // 调用方式
    // logMessage(DEBUG, "hello %f, %d, %c", 3.14, 10, 'C');
    std::string level_str(int level)
    {
        switch (level)
        {
        case DEBUG:
            return "DEBUG";
        case NORMAL:
            return "NORMAL";
        case WARNING:
            return "WARNING";
        case ERROR:
            return "ERROR";
        case FATAL:
            return "FATAL";
        default:
            return nullptr;
        }
    }

    // 时间戳转化为时间 毫秒级
    std::string Stamp2Time(const time_t timestamp)
    {
        // int ms = timestamp % 1000;                // 取毫秒
        // time_t tick = (time_t)(timestamp / 1000); // 转换时间
        // struct tm tm;
        // char s[40];
        // tm = *localtime(&tick);
        // strftime(s, sizeof(s), "%Y-%m-%d %H:%M:%S", &tm);
        // std::string str(s);
        // str = str + " " + std::to_string(ms);
        // return str;

        struct tm *timeinfo;
        int year, month, day, hour, minute, second;

        timeinfo = localtime(&timestamp);
        year = timeinfo->tm_year + 1900;
        month = timeinfo->tm_mon + 1;
        day = timeinfo->tm_mday;
        hour = timeinfo->tm_hour;
        minute = timeinfo->tm_min;
        second = timeinfo->tm_sec;

        char buf[64];
        bzero(buf, 64);
        sprintf(buf, "%04d-%02d-%02d %02d:%02d:%02d", year, month, day, hour, minute, second);
        return std::string(buf);
    }

    void logMessage(int level, const char *format, ...)
    {
        // 先做出:[日志等级] [时间戳/时间] [pid]
        // char logprefix[NUM];
        // snprintf(logprefix, sizeof(logprefix), "[%s][%ld][pid: %d]",
        //          level_str(level), (long int)time(nullptr), getpid());
        std::string pro = "";
        pro += "[";
        pro += level_str(level);
        pro += "]";

        // // 时间表示做了简化(用时间戳)
        // pro += "[";
        // pro += std::to_string((long int)time(nullptr));
        // pro += "]";
        // 也可以直接具体时间表示(不用时间戳)
        time_t curtime = time(NULL);
        pro += "[";
        pro += Stamp2Time(curtime);
        pro += "]";

        pro += "[";
        pro += std::to_string(getpid());
        pro += "]";
        // 基本信息完成;

        char logcontent[1024];
        va_list arg;
        va_start(arg, format);
        // 直接获取出格式化出的文本,不用自己去分析format,自己拼接
        vsnprintf(logcontent, sizeof(logcontent), format, arg);

        // 打印日志信息
        std::cout << pro << logcontent << std::endl;

        // // 输出到文件
        // FILE *err = fopen("err.log", "a");
        // FILE *log = fopen("log.log", "a");

        // if (err != nullptr && log != nullptr)
        // {
        //     FILE *curr = nullptr;
        //     if (level == DEBUG || level == NORMAL || level == WARNING)
        //         curr = log;
        //     if (level == ERROR || level == FATAL)
        //         curr = err;
        //     if (curr)
        //         fprintf(curr, "%s %s\n", pro.c_str(), logcontent);
        // }
        // fclose(log);
        // fclose(err);
        // // 注意一定要关闭文件,不然OS不刷新
    }
}
